#pragma once
#include <iostream>
#include <pthread.h>
#include <vector>
#include <queue>
#include <unistd.h>
#include "thread.hpp"
#include "myMtx.hpp"
#include "cond.hpp"
using namespace std;
#define NUMPTHREAD 5
#define NUMTAK 5
typedef void *(*func)(void *);
//饿汉单列模型
template <class T>
class pthreadPool
{
public:
    static pthreadPool<T> *get()
    {
        return _mypool;
    }

private:
    pthreadPool(int nump = NUMPTHREAD, int numt = NUMTAK) : _numpthread_t(nump), _tasknum(numt)
    {
        pthread_cond_init(&_full, nullptr);
        pthread_cond_init(&_empty, nullptr);
        pthread_mutex_init(&_mtx, nullptr);
    }

public:
    void start()
    {
        _func = pthreadPool<T>::enter;
        for (int i = 0; i < _numpthread_t; i++)
        {
            thread *p = new thread(_func, this);
            _pthread_t.push_back(p);
        }
    }
    void pop(T &x)
    {
        myMtx mtx(_mtx);
        myCond me(_empty, _mtx);
        myCond mf(_full, _mtx);
        while (_task.size() == 0)
        {
            mf.singal();
            me.wait();
        }
        sleep(5);
        cout << "消费" << pthread_self() << endl;
        x = _task.front();
        _task.pop();
    }
    static void *enter(void *args)
    {
        pthreadPool<T> *td = reinterpret_cast<pthreadPool<T> *>(args);
        while (true)
        {
            T ret;
            td->pop(ret);
            cout << ret << endl;
        }
        return nullptr;
    }
    // 插入任务
    void task(const T &x)
    {
        myMtx m(_mtx);
        myCond me(_empty, _mtx);
        myCond mf(_full, _mtx);
        while (_task.size() == _tasknum)
        {
            me.singal();
            mf.wait();
        }
        cout << "生产" << pthread_self() << endl;
        sleep(5);
        _task.push(x);
    }
    ~pthreadPool()
    {
        pthread_cond_destroy(&_full);
        pthread_cond_destroy(&_empty);
        pthread_mutex_destroy(&_mtx);
        for (auto &e : _pthread_t)
            delete e;
    }

private:
    vector<thread *> _pthread_t;
    queue<T> _task;
    func _func;
    int _numpthread_t;
    int _tasknum;
    pthread_mutex_t _mtx;
    pthread_cond_t _full;
    pthread_cond_t _empty;
    static pthreadPool<T> *_mypool;
};
template <class T>
class pthreadPool;
template <class T>
pthreadPool<T> *pthreadPool<T>::_mypool = new pthreadPool<T>();